



let DLX = require('./dlk/dlk').DLX;
let SudoHandler = require('./dlk/dlk').SudoHandler;

// let board = [
//     [3,7,0,0,0,0,0,6,0],
//     [9,0,4,0,2,6,0,0,1],
//     [2,0,1,0,0,3,0,0,0],
//
//     [0,0,0,6,0,4,9,7,0],
//     [7,0,9,0,3,0,0,0,0],
//     [0,0,0,0,0,8,0,2,0],
//
//     [0,1,3,9,0,0,0,0,0],
//     [0,0,0,0,8,0,0,0,0],
//     [0,0,0,0,0,7,2,8,0],
// ];

let board = [
    [0, 0, 6,  0, 0, 0,  0, 2, 0],
    [0, 0, 3,  0, 0, 0,  0, 0, 4],
    [8, 0, 0,  0, 0, 1,  5, 0, 0],

    [0, 0, 0,  5, 0, 0,  0, 9, 0],
    [0, 0, 0,  0, 9, 0,  0, 0, 0],
    [7, 1, 0,  3, 0, 8,  0, 0, 3],

    [0, 0, 4,  0, 3, 0,  0, 0, 0],
    [0, 8, 0,  0, 0, 0,  7, 1, 0],
    [0, 5, 0,  0, 6, 0,  0, 0, 0],
];


const S = 9;
const side = 3;
class B9X9{

    makeCoverGrid(board){
        let R = this.sudokuExactCover();
        for(let i = 1; i <= S; i++){
            for(let j = 1; j <= S; j++){
                let n = board[i - 1][j - 1];
                if (n != 0){ // zero out in the constraint board
                    for(let num = 1; num <= S; num++){
                        if (num != n){
                            let row = R[this.getIdx(i, j, num)];
                            for(let t = 0,tlen = row.length; t < tlen; ++t){
                                row[t] = 0;
                            }
                        }
                    }
                }
            }
        }
        return R;
    }

    sudokuExactCover(){
        let SIZE = 9;
        let R = [];

        let ROWS = SIZE * SIZE * SIZE;
        for(let i = 0; i < ROWS; ++i){
            R[i] = new Array(SIZE * SIZE * 4);
        }

        let hBase = 0;

        // row-column constraints
        for(let r = 1; r <= S; r++){
            for(let c = 1; c <= S; c++, hBase++){
                for(let n = 1; n <= S; n++){
                    R[this.getIdx(r, c, n)][hBase] = 1;
                }
            }
        }

        // row-number constraints
        for(let r = 1; r <= S; r++){
            for(let n = 1; n <= S; n++, hBase++){
                for(let c1 = 1; c1 <= S; c1++){
                    R[this.getIdx(r, c1, n)][hBase] = 1;
                }
            }
        }

        // column-number constraints

        for(let c = 1; c <= S; c++){
            for(let n = 1; n <= S; n++, hBase++){
                for(let r1 = 1; r1 <= S; r1++){
                    R[this.getIdx(r1, c, n)][hBase] = 1;
                }
            }
        }

        // box-number constraints

        for(let br = 1; br <= S; br += side){
            for(let bc = 1; bc <= S; bc += side){
                for(let n = 1; n <= S; n++, hBase++){
                    for(let rDelta = 0; rDelta < side; rDelta++){
                        for(let cDelta = 0; cDelta < side; cDelta++){
                            R[this.getIdx(br + rDelta, bc + cDelta, n)][hBase] = 1;
                        }
                    }
                }
            }
        }

        return R;
    }

    // row [1,S], col [1,S], num [1,S]
    getIdx( row,  col,  num){
        return (row - 1) * S * S + (col - 1) * S + (num - 1);
    }

    runSolver(board){
        let cover = this.makeCoverGrid(board);
        let dlx = new DLX(cover,new SudoHandler(9));
    }
}

let b4x4 = new B9X9();
b4x4.runSolver(board);

